/* unit-image.c
 *
 * Unit test for parser functions in image.c
 *
 *
 * Copyright (C) 2023 wolfSSL Inc.
 *
 * This file is part of wolfBoot.
 *
 * wolfBoot is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * wolfBoot is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
 */

/* Option to enable sign tool debugging */
/* Must also define DEBUG_WOLFSSL in user_settings.h */
#define WOLFBOOT_HASH_SHA256
#define EXT_FLASH
#define PART_UPDATE_EXT
#define NVM_FLASH_WRITEONCE

#if defined(ENCRYPT_WITH_AES256) || defined(ENCRYPT_WITH_AES128)
    #define WOLFSSL_AES_COUNTER
    #define WOLFSSL_AES_DIRECT
#endif
#if defined(ENCRYPT_WITH_AES256)
    #define WOLFSSL_AES_256
#endif
#if defined(ENCRYPT_WITH_CHACHA)
    #define HAVE_CHACHA
#endif
//#define WC_NO_HARDEN
#define ECC_TIMING_RESISTANT

#define WOLFSSL_USER_SETTINGS
#define ENCRYPT_KEY "123456789abcdef0123456789abcdef0123456789abcdef"
#define UNIT_TEST
#define WOLFBOOT_SIGN_ECC256
#define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_ECC256
#define __WOLFBOOT

#include <stdio.h>
#include <check.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "user_settings.h"
#include "wolfssl/wolfcrypt/sha.h"
#include "wolfboot/wolfboot.h"

#include "unit-keystore.c"

#include "image.c"

const uint8_t a;

static int ecc_init_fail = 1;
static int ecc_import_fail = 1;

static int verify_called = 0;

static int find_header_fail = 0;
static int find_header_called = 0;
static int find_header_mocked = 1;

static const unsigned char pubkey_digest[SHA256_DIGEST_SIZE] = {
  0x17, 0x20, 0xa5, 0x9b, 0xe0, 0x9b, 0x80, 0x0c, 0xaa, 0xc4, 0xf5, 0x3f,
  0xae, 0xe5, 0x72, 0x4f, 0xf2, 0x1f, 0x33, 0x53, 0xd1, 0xd4, 0xcd, 0x8b,
  0x5c, 0xc3, 0x4e, 0xda, 0xea, 0xc8, 0x4a, 0x68
};


static const unsigned char test_img_v200000000_signed_bin[] = {
      0x57, 0x4f, 0x4c, 0x46, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
  0x00, 0xc2, 0xeb, 0x0b, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x08, 0x00,
  0x77, 0x33, 0x29, 0x65, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
  0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00,
  0xda, 0x9c, 0xee, 0x7e, 0x12, 0xcf, 0xa0, 0xe1, 0xda, 0xa1, 0xb4, 0x23,
  0xbf, 0x31, 0xe5, 0xdd, 0x6f, 0x58, 0xfe, 0xd9, 0x8d, 0xb7, 0x7b, 0x31,
  0x6f, 0x7b, 0x01, 0x84, 0xe0, 0x63, 0x5e, 0xe9, 0x10, 0x00, 0x20, 0x00,
  0x17, 0x20, 0xa5, 0x9b, 0xe0, 0x9b, 0x80, 0x0c, 0xaa, 0xc4, 0xf5, 0x3f,
  0xae, 0xe5, 0x72, 0x4f, 0xf2, 0x1f, 0x33, 0x53, 0xd1, 0xd4, 0xcd, 0x8b,
  0x5c, 0xc3, 0x4e, 0xda, 0xea, 0xc8, 0x4a, 0x68, 0x20, 0x00, 0x40, 0x00,
  0xb0, 0x22, 0xb3, 0x91, 0xf7, 0x4e, 0xe1, 0x37, 0x6c, 0xb5, 0x64, 0x2e,
  0xe6, 0x80, 0x4b, 0xcb, 0xa7, 0x1d, 0xa1, 0xa7, 0x16, 0x2e, 0x4b, 0xa5,
  0xee, 0x67, 0xd2, 0x02, 0xff, 0x1b, 0xd3, 0x4c, 0xc6, 0x09, 0x62, 0x66,
  0x08, 0x4c, 0xfc, 0x32, 0x4b, 0x47, 0x56, 0xe0, 0x9b, 0x98, 0xd9, 0xa4,
  0x2a, 0x5e, 0x53, 0xd3, 0xb4, 0xde, 0x80, 0xe1, 0x9a, 0x95, 0x2a, 0x58,
  0xc9, 0xd6, 0x9a, 0x2a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0x54, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6d, 0x61,
  0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a
};


static const unsigned char test_img_v200000000_wrong_signature_bin[] = {
      0x57, 0x4f, 0x4c, 0x46, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
  0x00, 0xc2, 0xeb, 0x0b, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x08, 0x00,
  0x77, 0x33, 0x29, 0x65, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
  0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00,
  0xda, 0x9c, 0xee, 0x7e, 0x12, 0xcf, 0xa0, 0xe1, 0xda, 0xa1, 0xb4, 0x23,
  0xbf, 0x31, 0xe5, 0xdd, 0x6f, 0x58, 0xfe, 0xd9, 0x8d, 0xb7, 0x7b, 0x31,
  0x6f, 0x7b, 0x01, 0x84, 0xe0, 0x63, 0x5e, 0xe9, 0x10, 0x00, 0x20, 0x00,
  0x17, 0x20, 0xa5, 0x9b, 0xe0, 0x9b, 0x80, 0x0c, 0xaa, 0xc4, 0xf5, 0x3f,
  0xae, 0xe5, 0x72, 0x4f, 0xf2, 0x1f, 0x33, 0x53, 0xd1, 0xd4, 0xcd, 0x8b,
  0x5c, 0xc3, 0x4e, 0xda, 0xea, 0xc8, 0x4a, 0x68, 0x20, 0x00, 0x40, 0x00,
  0xb0, 0x22, 0xb3, 0x91, 0xf7, 0x4e, 0xe1, 0x37, 0x6c, 0xb5, 0x64, 0x2f,
  0xe6, 0x80, 0x4b, 0xcb, 0xa7, 0x1d, 0xa1, 0xa7, 0x16, 0x2e, 0x4b, 0xa5,
  0xee, 0x67, 0xd2, 0x02, 0xff, 0x1b, 0xd3, 0x4c, 0xc6, 0x09, 0x62, 0x66,
  0x08, 0x4c, 0xfc, 0x32, 0x4b, 0x47, 0x56, 0xe0, 0x9b, 0x98, 0xd9, 0xa4,
  0x2a, 0x5e, 0x53, 0xd3, 0xb4, 0xde, 0x80, 0xe1, 0x9a, 0x95, 0x2a, 0x58,
  0xc9, 0xd6, 0x9a, 0x2a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0x54, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6d, 0x61,
  0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a
};

static const unsigned char test_img_v200000000_wrong_pubkey_bin[] = {
      0x57, 0x4f, 0x4c, 0x46, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
  0x00, 0xc2, 0xeb, 0x0b, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x08, 0x00,
  0x77, 0x33, 0x29, 0x65, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
  0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00,
  0xda, 0x9c, 0xee, 0x7e, 0x12, 0xcf, 0xa0, 0xe1, 0xda, 0xa1, 0xb4, 0x24,
  0xbf, 0x31, 0xe5, 0xdd, 0x6f, 0x58, 0xfe, 0xd9, 0x8d, 0xb7, 0x7b, 0x31,
  0x6f, 0x7b, 0x01, 0x84, 0xe0, 0x63, 0x5e, 0xe9, 0x10, 0x00, 0x20, 0x00,
  0x17, 0x20, 0xa5, 0x9b, 0xe0, 0x9b, 0x80, 0x0c, 0xaa, 0xc4, 0xf5, 0x3f,
  0xae, 0xe5, 0x72, 0x4f, 0xf2, 0x1f, 0x33, 0x53, 0xd1, 0xd4, 0xcd, 0x8b,
  0x5c, 0xc3, 0x4e, 0xda, 0xea, 0xc8, 0x4a, 0x68, 0x20, 0x00, 0x40, 0x00,
  0xb0, 0x22, 0xb3, 0x91, 0xf7, 0x4e, 0xe1, 0x37, 0x6c, 0xb5, 0x64, 0x2e,
  0xe6, 0x80, 0x4b, 0xcb, 0xa7, 0x1d, 0xa1, 0xa7, 0x16, 0x2e, 0x4b, 0xa5,
  0xee, 0x67, 0xd2, 0x02, 0xff, 0x1b, 0xd3, 0x4c, 0xc6, 0x09, 0x62, 0x66,
  0x08, 0x4c, 0xfc, 0x32, 0x4b, 0x47, 0x56, 0xe0, 0x9b, 0x98, 0xd9, 0xa4,
  0x2a, 0x5e, 0x53, 0xd3, 0xb4, 0xde, 0x80, 0xe1, 0x9a, 0x95, 0x2a, 0x58,
  0xc9, 0xd6, 0x9a, 0x2a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0x54, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6d, 0x61,
  0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a
};
static const unsigned int test_img_len = 275;


unsigned char test_img_v123_signed_bin[] = {
      0x57, 0x4f, 0x4c, 0x46, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
  0x7b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x08, 0x00,
  0x77, 0x33, 0x29, 0x65, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
  0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00,
  0x89, 0xbd, 0x89, 0x01, 0xb9, 0xaf, 0xa9, 0xbd, 0x78, 0x88, 0xba, 0xd1,
  0x97, 0xc1, 0x6f, 0xd0, 0x7f, 0x11, 0xbd, 0x29, 0x97, 0x4a, 0x10, 0x27,
  0xa0, 0x53, 0x8c, 0x32, 0x3d, 0xfc, 0xc9, 0x9b, 0x10, 0x00, 0x20, 0x00,
  0x17, 0x20, 0xa5, 0x9b, 0xe0, 0x9b, 0x80, 0x0c, 0xaa, 0xc4, 0xf5, 0x3f,
  0xae, 0xe5, 0x72, 0x4f, 0xf2, 0x1f, 0x33, 0x53, 0xd1, 0xd4, 0xcd, 0x8b,
  0x5c, 0xc3, 0x4e, 0xda, 0xea, 0xc8, 0x4a, 0x68, 0x20, 0x00, 0x40, 0x00,
  0xfc, 0x1d, 0x02, 0x10, 0xb7, 0x60, 0x63, 0x7b, 0x55, 0xe0, 0x0e, 0xd5,
  0xb0, 0x64, 0xcd, 0x14, 0x9c, 0x1c, 0x80, 0x5f, 0x02, 0xb5, 0x54, 0x67,
  0x54, 0x93, 0x6d, 0xaf, 0x72, 0x74, 0x7b, 0x96, 0x94, 0x5c, 0x62, 0xb2,
  0x6d, 0x0f, 0xc9, 0xf4, 0x9f, 0x82, 0xa7, 0xd4, 0x28, 0xb9, 0x4c, 0x64,
  0x01, 0x5d, 0x03, 0x0f, 0x81, 0x05, 0x13, 0xf1, 0xe0, 0xbd, 0xdc, 0xe2,
  0x17, 0x84, 0xa3, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0x54, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6d, 0x61,
  0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a
};
unsigned int test_img_v123_signed_bin_len = 275;


static uint16_t _find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr)
{
    uint8_t *p = haystack;
    uint16_t len;
    const volatile uint8_t *max_p = (haystack - IMAGE_HEADER_OFFSET) +
                                                    IMAGE_HEADER_SIZE;
    *ptr = NULL;
    if (p > max_p) {
        printf("Illegal address (too high)\n");
        return 0;
    }
    while ((p + 4) < max_p) {
        if ((p[0] == 0) && (p[1] == 0)) {
            printf("Explicit end of options reached\n");
            break;
        }
        if (*p == HDR_PADDING) {
            /* Padding byte (skip one position) */
            p++;
            continue;
        }
        /* Sanity check to prevent dereferencing unaligned half-words */
        if ((((unsigned long)p) & 0x01) != 0) {
            p++;
            continue;
        }
        len = p[2] | (p[3] << 8);
        if ((4 + len) > (uint16_t)(IMAGE_HEADER_SIZE - IMAGE_HEADER_OFFSET)) {
            printf("This field is too large (bigger than the space available "
                     "in the current header)\n");
            printf("%d %d %d\n", len, IMAGE_HEADER_SIZE, IMAGE_HEADER_OFFSET);
            break;
        }
        if (p + 4 + len > max_p) {
            printf("This field is too large and would overflow the image "
                     "header\n");
            break;
        }
        if ((p[0] | (p[1] << 8)) == type) {
            *ptr = (p + 4);
            return len;
        }
        p += 4 + len;
    }
    return 0;
}

uint16_t wolfBoot_get_blob_type(uint8_t *addr)
{
    return HDR_IMG_TYPE_APP;
}

uint16_t wolfBoot_find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr)
{
    find_header_called++;
    if (find_header_mocked) {
        if (find_header_fail) {
            return -1;
        } else {
            return sizeof(uint16_t);
        }
    } else {
        return _find_header(haystack, type, ptr);
    }
}


int wc_ecc_init(ecc_key* key) {
    if (ecc_init_fail)
        return -1;
    return 0;
}

int wc_ecc_free(ecc_key *key) {
    return 0;
}

int wc_ecc_import_unsigned(ecc_key* key, const byte* qx, const byte* qy,
                   const byte* d, int curve_id)
{
    if (ecc_import_fail)
        return -1;
    
    key->type = ECC_PUBLICKEY;
    return 0;
}


int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash,
                    word32 hashlen, int* res, ecc_key* key)
{
    verify_called++;
    *res = 1;
    return 0;
}

START_TEST(test_verify_signature)
{
    uint8_t pubkey[32];
    struct wolfBoot_image test_img;
    
    test_img.part = PART_UPDATE;
    test_img.fw_size = test_img_len;
    test_img.fw_base = 0;

    wolfBoot_verify_signature(0, NULL, NULL);
    ck_assert_int_eq(verify_called, 0);

    ecc_init_fail = 1;
    wolfBoot_verify_signature(0, NULL, pubkey);
    ck_assert_int_eq(verify_called, 0);

    ecc_init_fail = 0;
    verify_called = 0;
    ecc_import_fail = 1;
    wolfBoot_verify_signature(0, NULL, pubkey);
    ck_assert_int_eq(verify_called, 0);

    ecc_init_fail = 0;
    ecc_import_fail = 0;
    verify_called = 0;
    find_header_mocked = 0;
    ext_flash_erase(0, 2 * WOLFBOOT_SECTOR_SIZE);
    ext_flash_write(0, test_img_v200000000_signed_bin,
            test_img_len);
    wolfBoot_verify_signature(0, &test_img, pubkey);
    ck_assert_int_eq(verify_called, 1);
}
END_TEST


START_TEST(test_sha_ops)
{
    uint8_t hash[SHA256_DIGEST_SIZE];
    static uint8_t FlashImg[32 * 1024];
    uint8_t *retp = NULL;
    struct wolfBoot_image test_img;
    uint32_t offset;
    uint32_t sz = 0;
    find_header_mocked = 1;
    memset(&test_img, 0, sizeof(struct wolfBoot_image));
    test_img.part = PART_BOOT;
    test_img.fw_size = 0x1000;
    test_img.fw_base = FlashImg;

    /* Test get_sha_block */
    offset = 0x2000;
    retp = get_sha_block(&test_img, offset);
    ck_assert_ptr_null(retp);

    offset = 0x100;
    retp = get_sha_block(&test_img, offset);
    ck_assert_ptr_eq(retp, FlashImg + offset);

    test_img.part = PART_UPDATE;
    test_img.fw_size = 0x1000;
    test_img.fw_base = 0x0000;

    offset = 0x2000;
    retp = get_sha_block(&test_img, offset);
    ck_assert_ptr_null(retp);

    offset = 0x100;
    retp = get_sha_block(&test_img, offset);
    ck_assert_ptr_eq(retp, ext_hash_block);

    /* Test wolfBoot_peek_image */
    hdr_cpy_done = 0;
    offset = 0x100;
    retp = get_sha_block(&test_img, offset);
    ck_assert_ptr_eq(retp, ext_hash_block);
    retp = wolfBoot_peek_image(&test_img, offset, NULL);
    ck_assert_ptr_eq(retp, ext_hash_block);
    retp = wolfBoot_peek_image(&test_img, offset, &sz);
    ck_assert_ptr_eq(retp, ext_hash_block);
    ck_assert_uint_eq(sz, WOLFBOOT_SHA_BLOCK_SIZE);

    /* Test image_sha256 */

    /* NULL img */
    ck_assert_int_lt(image_sha256(NULL, hash), 0);

    /* Too short, internal partition field */
    test_img.part = PART_BOOT;
    test_img.fw_size = 0x1000;
    ck_assert_int_lt(image_sha256(&test_img, hash), 0);

    /* Ext partition with a valid SHA */
    find_header_mocked = 0;
    find_header_fail = 0;
    hdr_cpy_done = 0;
    ext_flash_write(0, test_img_v200000000_signed_bin,
            test_img_len);
    test_img.part = PART_UPDATE;
    test_img.fw_base = 0;
    test_img.fw_size = test_img_len;
    ck_assert_int_eq(image_sha256(&test_img, hash), 0);

    /* key_sha256 */
    key_sha256(0, hash);
    ck_assert_mem_eq(hash, pubkey_digest, SHA256_DIGEST_SIZE);
}
END_TEST

START_TEST(test_headers)
{
    struct wolfBoot_image img;
    uint16_t type;
    void *ptr;
    uint16_t ret;
    uint32_t sz;
    memset(&img, 0, sizeof(struct wolfBoot_image));


    /* Test get_header() */
    img.part = PART_BOOT;
    find_header_fail = 1;
    find_header_called = 0;
    ret = get_header(&img, type, &ptr);
    ck_assert_uint_eq(ret, 0xFFFF);
    ck_assert_int_eq(find_header_called, 1);

    img.part = PART_BOOT;
    find_header_fail = 0;
    find_header_called = 0;
    ret = get_header(&img, type, &ptr);
    ck_assert_uint_ne(ret, 0xFFFF);
    ck_assert_int_eq(find_header_called, 1);

    img.part = PART_UPDATE;
    find_header_fail = 1;
    find_header_called = 0;
    ret = get_header(&img, type, &ptr);
    ck_assert_uint_eq(ret, 0xFFFF);
    ck_assert_int_eq(find_header_called, 1);

    img.part = PART_UPDATE;
    find_header_fail = 0;
    find_header_called = 0;
    ret = get_header(&img, type, &ptr);
    ck_assert_uint_ne(ret, 0xFFFF);
    ck_assert_int_eq(find_header_called, 1);

    /* Test get_img_hdr */
    img.part = PART_BOOT;
    img.hdr = (void *)0xAABBCCDD;
    ptr = get_img_hdr(&img);
    ck_assert_ptr_eq(ptr, img.hdr);

    img.part = PART_UPDATE;
    img.hdr = 0;
    ptr = get_img_hdr(&img);
    ck_assert_ptr_eq(ptr, hdr_cpy);

    /* Test image_size */
    sz = wolfBoot_image_size(test_img_v200000000_signed_bin);
    ck_assert_uint_eq(sz, test_img_len - 256);
}

START_TEST(test_verify_authenticity)
{
    struct wolfBoot_image test_img;
    int ret;
    memset(&test_img, 0, sizeof(struct wolfBoot_image));
    test_img.part = PART_UPDATE;

    /* Wrong sha field */
    find_header_mocked = 1;
    ret = wolfBoot_verify_authenticity(&test_img);
    ck_assert_int_eq(ret, -1);
    
    /* Wrong pubkey  */
    find_header_mocked = 0;
    hdr_cpy_done = 0;
    ext_flash_write(0, test_img_v200000000_wrong_pubkey_bin,
            test_img_len);
    ret = wolfBoot_verify_authenticity(&test_img);
    ck_assert_int_lt(ret, 0);
    
    /* Wrong signature  */
    find_header_mocked = 0;
    find_header_fail = 0;
    hdr_cpy_done = 0;
    ext_flash_write(0, test_img_v200000000_wrong_signature_bin,
            test_img_len);
    ret = wolfBoot_verify_authenticity(&test_img);
    ck_assert_int_lt(ret, 0);

    /* Correct image  */
    find_header_mocked = 0;
    ecc_import_fail = 0;
    ecc_init_fail = 0;
    hdr_cpy_done = 0;
    ext_flash_erase(0, 2 * WOLFBOOT_SECTOR_SIZE);
    ext_flash_write(0, test_img_v123_signed_bin,
            test_img_v123_signed_bin_len);
    test_img.signature_ok = 1; /* mock for VERIFY_FN */
    ret = wolfBoot_verify_authenticity(&test_img);
    ck_assert_int_eq(ret, 0);

}
END_TEST

START_TEST(test_verify_integrity)
{
    struct wolfBoot_image test_img;
    int ret;
    /* Wrong sha field */
    find_header_mocked = 1;
    ret = wolfBoot_verify_integrity(&test_img);
    ck_assert_int_eq(ret, -1);

    /* Correct image  */
    find_header_mocked = 0;
    find_header_fail = 0;
    hdr_cpy_done = 0;
    ecc_import_fail = 0;
    ecc_init_fail = 0;
    memset(&test_img, 0, sizeof(struct wolfBoot_image));
    ext_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_SECTOR_SIZE);
    ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS,
            test_img_v123_signed_bin,
            test_img_v123_signed_bin_len);
    ret = wolfBoot_open_image(&test_img, PART_UPDATE);
    ck_assert_int_eq(ret, 0);
    ck_assert_uint_eq(test_img.hdr, WOLFBOOT_PARTITION_UPDATE_ADDRESS);
    ret = wolfBoot_verify_integrity(&test_img);
    ck_assert_int_eq(ret, 0);
}
END_TEST

START_TEST(test_open_image)
{
    struct wolfBoot_image img;
    int ret;


    /* invalid argument */
    ret = wolfBoot_open_image(NULL, PART_UPDATE);
    ck_assert_int_eq(ret, -1);

    /* Empty flash */
    find_header_mocked = 0;
    hdr_cpy_done = 0;
    ext_flash_erase(0, WOLFBOOT_SECTOR_SIZE);
    ret = wolfBoot_open_image(&img, PART_UPDATE);
    ck_assert_int_eq(ret, -1);

    /* Swap partition */
    ret = wolfBoot_open_image(&img, PART_SWAP);
    ck_assert_uint_eq(img.hdr_ok, 1);
    ck_assert_ptr_eq(img.hdr, WOLFBOOT_PARTITION_SWAP_ADDRESS);
    ck_assert_ptr_eq(img.hdr, img.fw_base);
    ck_assert_uint_eq(img.fw_size, WOLFBOOT_SECTOR_SIZE);
    
    /* Valid image */
    hdr_cpy_done = 0;
    ext_flash_write(0, test_img_v200000000_signed_bin,
            test_img_len);
    ret = wolfBoot_open_image(&img, PART_UPDATE);
    ck_assert_int_eq(ret, 0);
    ck_assert_uint_eq(img.hdr_ok, 1);
    ck_assert_ptr_eq(img.hdr, WOLFBOOT_PARTITION_UPDATE_ADDRESS);
    ck_assert_ptr_eq(img.fw_base, WOLFBOOT_PARTITION_UPDATE_ADDRESS + 256);

}
END_TEST


Suite *wolfboot_suite(void)
{
    /* Suite initialization */
    Suite *s = suite_create("wolfBoot");

    TCase* tcase_verify_signature = tcase_create("verify_signature");
    tcase_set_timeout(tcase_verify_signature, 20);
    tcase_add_test(tcase_verify_signature, test_verify_signature);
    suite_add_tcase(s, tcase_verify_signature);

    TCase* tcase_sha_ops = tcase_create("sha_ops");
    tcase_set_timeout(tcase_sha_ops, 20);
    tcase_add_test(tcase_sha_ops, test_sha_ops);
    suite_add_tcase(s, tcase_sha_ops);

    TCase* tcase_headers = tcase_create("headers");
    tcase_set_timeout(tcase_headers, 20);
    tcase_add_test(tcase_headers, test_headers);
    suite_add_tcase(s, tcase_headers);
    
    TCase* tcase_verify_authenticity = tcase_create("verify_authenticity");
    tcase_set_timeout(tcase_verify_authenticity, 20);
    tcase_add_test(tcase_verify_authenticity, test_verify_authenticity);
    suite_add_tcase(s, tcase_verify_authenticity);
    
    TCase* tcase_verify_integrity = tcase_create("verify_integrity");
    tcase_set_timeout(tcase_verify_integrity, 20);
    tcase_add_test(tcase_verify_integrity, test_verify_integrity);
    suite_add_tcase(s, tcase_verify_integrity);
    
    TCase* tcase_open_image = tcase_create("open_image");
    tcase_set_timeout(tcase_open_image, 20);
    tcase_add_test(tcase_open_image, test_open_image);
    suite_add_tcase(s, tcase_open_image);
    return s;
}

int main(void)
{
    int fails;
    Suite *s = wolfboot_suite();
    SRunner *sr = srunner_create(s);
    srunner_run_all(sr, CK_NORMAL);
    fails = srunner_ntests_failed(sr);
    srunner_free(sr);
    return fails;
}
